#include "XWindow.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "XFont.h"

#include "XWinSystem.h"
#include "String.h"
#include "Error.h"
#include "XBitmap.h"
#include "ET_stdio.h"

static char *XXFontFName[] = {
	"times",
	"helvet",
	"courie",
	"symbol",
	"chicag",
	"avgard",
	"bookmn",
	"ceslbk",
	"nhelve",
	"palati",
	"zchanc",
	"zdingb",
	0
};

static char *XFontMap[][5] = {
	{ "times",                "medium",   "bold",     "r",    "i" },
	{ "helvetica",            "medium",   "bold",     "r",    "o" },
	{ "courier",              "medium",   "bold",     "r",    "o" },
	{ "symbol",               "medium",   "medium",   "r",    "r" },
	{ "lucida sans",          "medium",   "bold",     "r",    "i" },
	{ "avantgarde",           "demi",     "book",     "r",    "o" },
	{ "bookman",              "light",    "demi",     "r",    "i" },
	{ "new century schoolbook", "medium", "bold",     "r",    "i" },
	{ "helvetica",            "medium",   "bold",     "r",    "o" },
	{ "palatino",             "medium",   "bold",     "r",    "i" },
	{ "zapfchancery",         "medium",   "medium",   "i",    "i" },
	{ "zapfdingbats",         "medium",   "medium",   "r",    "r" },
	{ 0,                      0,          0,          0,      0     }
};

//---- XServerFont -------------------------------------------------------------

XServerFont::XServerFont(FontFamily *fam, int ps, GrFace fc, XFontStruct *xFont)
														: Font(fam, ps, fc)
{
	if (xFont) {
		register int i, j;
		register byte w;
		
		if (size == 0) {
			u_long val;
			if (XGetFontProperty(xFont, XA_POINT_SIZE, &val))
				size= (short) val/10;
			else
				size= 12;
		}
				
		xfid= xFont->fid;
		ht= xFont->max_bounds.ascent;
		ht++;
		bs= xFont->max_bounds.descent;
		bs--;
		ils= xFont->ascent + xFont->descent;
		ils= ht+bs+3;
		
		if (xFont->per_char && xFont->default_char < 256)
			w= (byte) xFont->per_char[xFont->default_char].width;
		else
			w= xFont->max_bounds.width;

		for (i= 0; i < 256; i++)
			cw[i]= w;
		
		if (xFont->per_char) {
			if (xFont->min_byte1 == 0 && xFont->max_byte1 == 0)
				for (i= xFont->min_char_or_byte2, j= 0; i <= xFont->max_char_or_byte2; i++, j++)
					cw[i]= (byte) xFont->per_char[j].width;
			else
				fprintf(stderr, "can't handle two-byte fonts\n");
		}
		XFreeFontInfo(NULL, xFont, 0);
	}
}

DevBitmap *XServerFont::CharAsBitmap(u_int c, Point *offset)
{
	XGCValues gcv;
	XCharStruct cc;
	Pixmap pm;
	GC gc;
	Point e;
	int dir, dd, aa;

	XQueryTextExtents(XWinSystem::display, GetId(), (char*)&c, 1, &dir, &aa, &dd, &cc);
	e.x= cc.rbearing - cc.lbearing;
	e.y= cc.ascent + cc.descent;
	if (e.x <= 0)
		e.x= 1;
	if (e.y <= 0)
		e.y= 1;
	offset->x= cc.lbearing;
	offset->y= cc.ascent;
	pm= XWinSystem::CreatePixmap(e, 1);
	gcv.background= 0;
	gcv.foreground= 0;
	gc= XWinSystem::CreateGC(pm, GCForeground|GCBackground, &gcv);
	XFillRectangle(XWinSystem::display, pm, gc, 0, 0, e.x+1, e.y+1);
	XSetForeground(XWinSystem::display, gc, 1);
	XSetFont(XWinSystem::display, gc, GetId());
	XDrawString(XWinSystem::display, pm, gc, -cc.lbearing, cc.ascent, (const char*) &c, 1);
	XFreeGC(XWinSystem::display, gc);

	XImage *im= XGetImage(XWinSystem::display, pm, 0, 0, e.x, e.y,
													(u_long) AllPlanes, ZPixmap);
	XFreePixmap(XWinSystem::display, pm);

	if (im)
		return new XBitmap(e, im);
	return 0;
}

//---- XFontManager ------------------------------------------------------------

bool TryFamily(const char *nm, const char *wh, const char *sl)
{
	char xname[200];
	sprintf(xname, "-*-%s-%s-%s-*-*-*-*-*-*-*-*-*-*", nm, wh, sl);
	if (gDebug) fprintf(stderr, "0: %s:", xname);
	XFontStruct *xf= XLoadQueryFont(XWinSystem::display, xname);
	if (xf) {
		if (gDebug) fprintf(stderr, "found\n");
		XFreeFont(XWinSystem::display, xf);
		return TRUE;
	}
	if (gDebug) fprintf(stderr, "not found\n");
	return FALSE;
}

XFontStruct *TryFont(const char *nm, int fid, GrFace fc, int ps)
{
	char xname[200],
		**xm= XFontMap[fid],
		*weight= (fc & eFaceBold) ? xm[2] : xm[1],
		*slant= (fc & eFaceItalic) ? xm[4] : xm[3];
	XFontStruct *xf;

	if (!TryFamily(nm, weight, slant))
		return 0;

	sprintf(xname, "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-*-*", nm, weight, slant, ps);
	if (gDebug) fprintf(stderr, "1: %s\n", xname);
	if ((xf= XLoadQueryFont(XWinSystem::display, xname)))
		return xf;
	sprintf(xname, "-*-%s-%s-%s-*-*-*-%d-*-*-*-*-*-*", nm, weight, slant, ps*10);
	if (gDebug) fprintf(stderr, "2: %s\n", xname);
	if ((xf= XLoadQueryFont(XWinSystem::display, xname)))
		return xf;
	// try OpenWindows outline fonts (ps == 0)
	sprintf(xname, "-*-%s-%s-%s-*-*-0-*-*-*-*-*-*-*", nm, weight, slant);
	if (gDebug) fprintf(stderr, "3: %s\n", xname);
	if ((xf= XLoadQueryFont(XWinSystem::display, xname)))
		return xf;
	return 0;
}

Font* XFontManager::MakeFont(FontFamily *ff, int ps, GrFace fc, bool dflt)
{
	int fid= ff->Fid();
	char xname[200], **xm= XFontMap[fid];
	XFontStruct *xf;

	if (gDebug)
		fprintf(stderr, "%d %d %d\n", fid, ps, fc);

	if (xm[0]) {    // try standard X fonts
		if (xf= TryFont(xm[0], fid, fc, ps))
			return new XServerFont(ff, ps, fc, xf);
		if (xf= TryFont("lucida sans", fid, fc, ps))
			return new XServerFont(ff, ps, fc, xf);
	}
	// try ET++ standard fonts (ps == 0)
	sprintf(xname, "%s%02d%s", XXFontFName[fid], ps, gFontManager->StyleString(fc));
	if (xf= XLoadQueryFont(XWinSystem::display, xname))
		return new XServerFont(ff, ps, fc, xf);

	if (dflt) {
		char *otherfont;
		// try X default fonts
		switch (fid) {
		case eFontCourier:
			otherfont= "fixed";
			break;
		case eFontChicago:
			otherfont= "variable";
			break;
		default:
			otherfont= "8x13";
			break;
		}
		fprintf(stderr, "can't load font %s; trying %s\n", xname, otherfont);
		if ((xf= XLoadQueryFont(XWinSystem::display, otherfont)))
			return new XServerFont(ff, ps, fc, xf);

		fprintf(stderr, "can't load font %s; giving up\n", otherfont);
	}
	return 0;
}

void XServerFont::Scale(int s)
{
	for (int i= 0; i < 256; i++)
		cw[i]= (cw[i]*s) / (u_short)size;
	ht= (ht*s)/size;
	bs= (bs*s)/size;
	ils= (ils*s)/size;
	size= s;
}

Font *XFontManager::ScaleFont(FontFamily *ff, int ps, GrFace face)
{
	if (ps < 24)
		return FontManager::ScaleFont(ff, ps, face);
	XServerFont *xf= (XServerFont*) new_Font(ff->Fid(), ps/10, face);
	XServerFont *xff= new XServerFont(ff, ps/10, face);
	*xff= *xf;
	xff->Scale(ps);
	return xff;
}

